#Library

#1. a. Which variables are continuous/numerical? Which are ordinal? Which are nominal?
#b. What are the methods for transforming categorical variables? 
#c. Carry out and demonstrate data transformation where necessary. 

setwd("C:/Users/Admin/Documents/Predictive Anal ASM1")
housingvaluation <- read.csv("HousingValuation.csv")

summary(housingvaluation)
       Id            LotArea          LotShape     LandContour         Utilities          LotConfig        
 Min.   :   1.0   Min.   :  1300   Min.   :1.000   Length:1454        Length:1454        Length:1454       
 1st Qu.: 365.2   1st Qu.:  7544   1st Qu.:3.000   Class :character   Class :character   Class :character  
 Median : 732.5   Median :  9478   Median :4.000   Mode  :character   Mode  :character   Mode  :character  
 Mean   : 731.3   Mean   : 10521   Mean   :3.591                                                           
 3rd Qu.:1095.8   3rd Qu.: 11604   3rd Qu.:4.000                                                           
 Max.   :1460.0   Max.   :215245   Max.   :4.000                                                           
                                                                                                           
    Slope            DwellClass        OverallQuality   OverallCondition   YearBuilt    ExteriorCondition 
 Length:1454        Length:1454        Min.   : 1.000   Min.   :2.000    Min.   :1872   Length:1454       
 Class :character   Class :character   1st Qu.: 5.000   1st Qu.:5.000    1st Qu.:1954   Class :character  
 Mode  :character   Mode  :character   Median : 6.000   Median :5.000    Median :1973   Mode  :character  
                                       Mean   : 6.103   Mean   :5.576    Mean   :1972                     
                                       3rd Qu.: 7.000   3rd Qu.:6.000    3rd Qu.:2000                     
                                       Max.   :10.000   Max.   :9.000    Max.   :2010                     
                                                                         NA's   :13                       
 BasementCondition     TotalBSF     CentralAir         LowQualFinSF       LivingArea      FullBath    
 Length:1454        Min.   :   0   Length:1454        Min.   :  0.000   Min.   : 334   Min.   :0.000  
 Class :character   1st Qu.: 796   Class :character   1st Qu.:  0.000   1st Qu.:1131   1st Qu.:1.000  
 Mode  :character   Median : 992   Mode  :character   Median :  0.000   Median :1466   Median :2.000  
                    Mean   :1058                      Mean   :  5.869   Mean   :1517   Mean   :1.566  
                    3rd Qu.:1300                      3rd Qu.:  0.000   3rd Qu.:1777   3rd Qu.:2.000  
                    Max.   :6110                      Max.   :572.000   Max.   :5642   Max.   :3.000  
                                                                        NA's   :10                    
    HalfBath       BedroomAbvGr   KitchenQuality      KitchenAbvGr   TotalRmsAbvGrd    Fireplaces    
 Min.   :0.0000   Min.   :0.000   Length:1454        Min.   :0.000   Min.   : 2.00   Min.   :0.0000  
 1st Qu.:0.0000   1st Qu.:2.000   Class :character   1st Qu.:1.000   1st Qu.: 5.00   1st Qu.:0.0000  
 Median :0.0000   Median :3.000   Mode  :character   Median :1.000   Median : 6.00   Median :1.0000  
 Mean   :0.3831   Mean   :2.869                      Mean   :1.047   Mean   : 6.52   Mean   :0.6142  
 3rd Qu.:1.0000   3rd Qu.:3.000                      3rd Qu.:1.000   3rd Qu.: 7.00   3rd Qu.:1.0000  
 Max.   :2.0000   Max.   :8.000                      Max.   :3.000   Max.   :14.00   Max.   :3.0000  
                                                                                                     
  GarageType          GarageCars     PavedDrive           PoolArea       OpenPorchSF         MoSold      
 Length:1454        Min.   :0.000   Length:1454        Min.   :  0.00   Min.   :  0.00   Min.   : 1.000  
 Class :character   1st Qu.:1.000   Class :character   1st Qu.:  0.00   1st Qu.:  0.00   1st Qu.: 5.000  
 Mode  :character   Median :2.000   Mode  :character   Median :  0.00   Median : 25.00   Median : 6.000  
                    Mean   :1.771                      Mean   :  2.77   Mean   : 46.37   Mean   : 6.319  
                    3rd Qu.:2.000                      3rd Qu.:  0.00   3rd Qu.: 68.00   3rd Qu.: 8.000  
                    Max.   :4.000                      Max.   :738.00   Max.   :547.00   Max.   :12.000  
                                                                                                         
     YrSold       SalePrice     
 Min.   :2006   Min.   : 34900  
 1st Qu.:2007   1st Qu.:130000  
 Median :2008   Median :163250  
 Mean   :2008   Mean   :181112  
 3rd Qu.:2009   3rd Qu.:214000  
 Max.   :2010   Max.   :755000  
                                
View(housingvaluation)
str(housingvaluation)
'data.frame':   1454 obs. of  32 variables:
 $ Id               : int  3 4 5 6 8 12 14 15 17 21 ...
 $ LotArea          : int  11250 9550 14260 14115 10382 11924 10652 10920 11241 14215 ...
 $ LotShape         : int  3 3 3 3 3 3 3 3 3 3 ...
 $ LandContour      : chr  "Lvl" "Lvl" "Lvl" "Lvl" ...
 $ Utilities        : chr  "AllPub" "AllPub" "AllPub" "AllPub" ...
 $ LotConfig        : chr  "Inside" "Corner" "FR2" "Inside" ...
 $ Slope            : chr  "Gtl" "Gtl" "Gtl" "Gtl" ...
 $ DwellClass       : chr  "1Fam" "1Fam" "1Fam" "1Fam" ...
 $ OverallQuality   : int  7 7 8 5 7 9 7 6 6 8 ...
 $ OverallCondition : int  5 5 5 5 6 5 5 5 7 5 ...
 $ YearBuilt        : int  2001 1915 2000 1993 1973 2005 2006 1960 1970 2005 ...
 $ ExteriorCondition: chr  "TA" "TA" "TA" "TA" ...
 $ BasementCondition: chr  "TA" "Gd" "TA" "TA" ...
 $ TotalBSF         : int  920 756 1145 796 1107 1175 1494 1253 1004 1158 ...
 $ CentralAir       : chr  "Y" "Y" "Y" "Y" ...
 $ LowQualFinSF     : int  0 0 0 0 0 0 0 0 0 0 ...
 $ LivingArea       : int  1786 1717 2198 1362 2090 2324 1494 1253 1004 2376 ...
 $ FullBath         : int  2 1 2 1 2 3 2 1 1 3 ...
 $ HalfBath         : int  1 0 1 1 1 0 0 1 0 1 ...
 $ BedroomAbvGr     : int  3 3 4 1 3 4 3 2 2 4 ...
 $ KitchenQuality   : chr  "Gd" "Gd" "Gd" "TA" ...
 $ KitchenAbvGr     : int  1 1 1 1 1 1 1 1 1 1 ...
 $ TotalRmsAbvGrd   : int  6 7 9 5 7 11 7 5 5 9 ...
 $ Fireplaces       : int  1 1 1 0 2 2 1 1 1 1 ...
 $ GarageType       : chr  "Attchd" "Detchd" "Attchd" "Attchd" ...
 $ GarageCars       : int  2 3 3 2 2 3 3 1 2 3 ...
 $ PavedDrive       : chr  "Y" "Y" "Y" "Y" ...
 $ PoolArea         : int  0 0 0 0 0 0 0 0 0 0 ...
 $ OpenPorchSF      : int  42 35 84 30 204 21 33 213 0 154 ...
 $ MoSold           : int  9 2 12 10 11 7 8 5 3 11 ...
 $ YrSold           : int  2008 2006 2008 2009 2009 2006 2007 2008 2010 2006 ...
 $ SalePrice        : int  223500 140000 250000 143000 200000 345000 279500 157000 149000 325300 ...

#Part B-Question 1

summary(housingvaluation)
    LotArea          LotShape      LandContour         Slope         OverallQuality   OverallCondition
 Min.   :  1300   Min.   :1.000   Min.   :0.0000   Min.   :0.00000   Min.   : 1.000   Min.   :2.000   
 1st Qu.:  7544   1st Qu.:3.000   1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.: 5.000   1st Qu.:5.000   
 Median :  9478   Median :4.000   Median :0.0000   Median :0.00000   Median : 6.000   Median :5.000   
 Mean   : 10521   Mean   :3.591   Mean   :0.1843   Mean   :0.06121   Mean   : 6.103   Mean   :5.576   
 3rd Qu.: 11604   3rd Qu.:4.000   3rd Qu.:0.0000   3rd Qu.:0.00000   3rd Qu.: 7.000   3rd Qu.:6.000   
 Max.   :215245   Max.   :4.000   Max.   :3.0000   Max.   :2.00000   Max.   :10.000   Max.   :9.000   
                                                                                                      
   YearBuilt    ExteriorCondition BasementCondition    TotalBSF      CentralAir      LowQualFinSF    
 Min.   :1872   Min.   :0.000     Min.   :0.000     Min.   :   0   Min.   :0.0000   Min.   :  0.000  
 1st Qu.:1954   1st Qu.:1.000     1st Qu.:2.000     1st Qu.: 796   1st Qu.:1.0000   1st Qu.:  0.000  
 Median :1973   Median :1.000     Median :2.000     Median : 992   Median :1.0000   Median :  0.000  
 Mean   :1972   Mean   :1.083     Mean   :1.963     Mean   :1058   Mean   :0.9354   Mean   :  5.869  
 3rd Qu.:2000   3rd Qu.:1.000     3rd Qu.:2.000     3rd Qu.:1300   3rd Qu.:1.0000   3rd Qu.:  0.000  
 Max.   :2010   Max.   :2.000     Max.   :3.000     Max.   :6110   Max.   :1.0000   Max.   :572.000  
 NA's   :13                                                                                          
   LivingArea      FullBath        HalfBath       BedroomAbvGr   KitchenQuality   KitchenAbvGr  
 Min.   : 334   Min.   :0.000   Min.   :0.0000   Min.   :0.000   Min.   :0.000   Min.   :0.000  
 1st Qu.:1131   1st Qu.:1.000   1st Qu.:0.0000   1st Qu.:2.000   1st Qu.:1.000   1st Qu.:1.000  
 Median :1466   Median :2.000   Median :0.0000   Median :3.000   Median :1.000   Median :1.000  
 Mean   :1517   Mean   :1.566   Mean   :0.3831   Mean   :2.869   Mean   :1.514   Mean   :1.047  
 3rd Qu.:1777   3rd Qu.:2.000   3rd Qu.:1.0000   3rd Qu.:3.000   3rd Qu.:2.000   3rd Qu.:1.000  
 Max.   :5642   Max.   :3.000   Max.   :2.0000   Max.   :8.000   Max.   :3.000   Max.   :3.000  
 NA's   :10                                                                                     
 TotalRmsAbvGrd    Fireplaces       GarageCars      PavedDrive       PoolArea       OpenPorchSF    
 Min.   : 2.00   Min.   :0.0000   Min.   :0.000   Min.   :0.000   Min.   :  0.00   Min.   :  0.00  
 1st Qu.: 5.00   1st Qu.:0.0000   1st Qu.:1.000   1st Qu.:2.000   1st Qu.:  0.00   1st Qu.:  0.00  
 Median : 6.00   Median :1.0000   Median :2.000   Median :2.000   Median :  0.00   Median : 25.00  
 Mean   : 6.52   Mean   :0.6142   Mean   :1.771   Mean   :1.858   Mean   :  2.77   Mean   : 46.37  
 3rd Qu.: 7.00   3rd Qu.:1.0000   3rd Qu.:2.000   3rd Qu.:2.000   3rd Qu.:  0.00   3rd Qu.: 68.00  
 Max.   :14.00   Max.   :3.0000   Max.   :4.000   Max.   :2.000   Max.   :738.00   Max.   :547.00  
                                                                                                   
     MoSold           YrSold       SalePrice      Utilities_AllPub Utilities_NoSeWa    LotConfig_Corner
 Min.   : 1.000   Min.   :2006   Min.   : 34900   Min.   :0.0000   Min.   :0.0000000   Min.   :0.0000  
 1st Qu.: 5.000   1st Qu.:2007   1st Qu.:130000   1st Qu.:1.0000   1st Qu.:0.0000000   1st Qu.:0.0000  
 Median : 6.000   Median :2008   Median :163250   Median :1.0000   Median :0.0000000   Median :0.0000  
 Mean   : 6.319   Mean   :2008   Mean   :181112   Mean   :0.9993   Mean   :0.0006878   Mean   :0.1802  
 3rd Qu.: 8.000   3rd Qu.:2009   3rd Qu.:214000   3rd Qu.:1.0000   3rd Qu.:0.0000000   3rd Qu.:0.0000  
 Max.   :12.000   Max.   :2010   Max.   :755000   Max.   :1.0000   Max.   :1.0000000   Max.   :1.0000  
                                                                                                       
 LotConfig_CulDSac LotConfig_FR2     LotConfig_FR3      LotConfig_Inside Dwellclass_Single_Family
 Min.   :0.00000   Min.   :0.00000   Min.   :0.000000   Min.   :0.0000   Min.   :0.0000          
 1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.000000   1st Qu.:0.0000   1st Qu.:1.0000          
 Median :0.00000   Median :0.00000   Median :0.000000   Median :1.0000   Median :1.0000          
 Mean   :0.06465   Mean   :0.03232   Mean   :0.002751   Mean   :0.7201   Mean   :0.8349          
 3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.000000   3rd Qu.:1.0000   3rd Qu.:1.0000          
 Max.   :1.00000   Max.   :1.00000   Max.   :1.000000   Max.   :1.0000   Max.   :1.0000          
                                                                                                 
 Dwellclass_Two_Family Dwellclass_Duplex Dwellclass_Townhouse_EndUnit Dwellclass_Townhouse_InsideUnite
 Min.   :0.00000       Min.   :0.00000   Min.   :0.0000               Min.   :0.00000                 
 1st Qu.:0.00000       1st Qu.:0.00000   1st Qu.:0.0000               1st Qu.:0.00000                 
 Median :0.00000       Median :0.00000   Median :0.0000               Median :0.00000                 
 Mean   :0.02132       Mean   :0.03576   Mean   :0.0784               Mean   :0.02957                 
 3rd Qu.:0.00000       3rd Qu.:0.00000   3rd Qu.:0.0000               3rd Qu.:0.00000                 
 Max.   :1.00000       Max.   :1.00000   Max.   :1.0000               Max.   :1.00000                 
                                                                                                      
 Twotypes_garage    Attachedtohome_garage Basement_garage   Buildin_garage    Carport_garage   
 Min.   :0.000000   Min.   :0.0000        Min.   :0.00000   Min.   :0.00000   Min.   :0.00000  
 1st Qu.:0.000000   1st Qu.:0.0000        1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.00000  
 Median :0.000000   Median :1.0000        Median :0.00000   Median :0.00000   Median :0.00000  
 Mean   :0.004126   Mean   :0.5983        Mean   :0.01307   Mean   :0.06052   Mean   :0.00619  
 3rd Qu.:0.000000   3rd Qu.:1.0000        3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.00000  
 Max.   :1.000000   Max.   :1.0000        Max.   :1.00000   Max.   :1.00000   Max.   :1.00000  
                                                                                               
 Detachedfromhome_garage
 Min.   :0.0000         
 1st Qu.:0.0000         
 Median :0.0000         
 Mean   :0.2641         
 3rd Qu.:1.0000         
 Max.   :1.0000         
                        

#PartB-Question 2 & 3


housingvaluation$Dwellclass_Single_Family <- as.numeric(housingvaluation$DwellClass == "1Fam")
housingvaluation$Dwellclass_Two_Family <- as.numeric(housingvaluation$DwellClass == "2fmCon")
housingvaluation$Dwellclass_Duplex <- as.numeric(housingvaluation$DwellClass == "Duplex")
housingvaluation$Dwellclass_Townhouse_EndUnit <- as.numeric(housingvaluation$DwellClass == "TwnhsE")
housingvaluation$Dwellclass_Townhouse_InsideUnite <- as.numeric(housingvaluation$DwellClass == "Twnhs")

housingvaluation <- housingvaluation[, !names(housingvaluation) %in% c("DwellClass")]

#Handle NA values of GrarageType variable

NA_numeric <- function(x, value) {
  ifelse(is.na(x), 0, as.numeric(x == value))
}

housingvaluation$Twotypes_garage <- NA_numeric(housingvaluation$GarageType, "2Types")
housingvaluation$Attachedtohome_garage <- NA_numeric(housingvaluation$GarageType, "Attchd")
housingvaluation$Basement_garage <- NA_numeric(housingvaluation$GarageType, "Basment")
housingvaluation$Buildin_garage <- NA_numeric(housingvaluation$GarageType, "BuiltIn")
housingvaluation$Carport_garage <- NA_numeric(housingvaluation$GarageType, "CarPort")
housingvaluation$Detachedfromhome_garage <- NA_numeric(housingvaluation$GarageType, "Detchd")


housingvaluation <- housingvaluation[, !names(housingvaluation) %in% c("GarageType")]
#Tranform ordinal varibles into numerical


housingvaluation$ExteriorCondition <- factor(housingvaluation$ExteriorCondition, levels=c("Gd","TA","Fa"), labels=c(2,1,0))
housingvaluation$ExteriorCondition <- as.numeric(as.character(housingvaluation$ExteriorCondition))

housingvaluation$CentralAir <- factor(housingvaluation$CentralAir, levels=c("N","Y"), 
labels=c(0,1))
housingvaluation$CentralAir <- as.numeric(as.character(housingvaluation$CentralAir))

housingvaluation$BasementCondition <-  factor(housingvaluation$BasementCondition, levels=c("Gd","TA","Fa","NB"), 
labels=c(3,2,1,0))
housingvaluation$BasementCondition <- as.numeric(as.character(housingvaluation$BasementCondition))

housingvaluation$KitchenQuality <- factor(housingvaluation$KitchenQuality, levels=c("Ex","Gd","TA","Fa"), 
labels=c(3,2,1,0))
housingvaluation$KitchenQuality <- as.numeric(as.character(housingvaluation$KitchenQuality))

housingvaluation$LandContour <- factor(housingvaluation$LandContour, levels=c("Low","HLS","Bnk","Lvl"), 
labels=c(3,2,1,0))
housingvaluation$LandContour <- as.numeric(as.character(housingvaluation$LandContour))

housingvaluation$PavedDrive <- factor(housingvaluation$PavedDrive, levels=c("Y","P","N"), 
labels=c(2,1,0))
housingvaluation$PavedDrive <- as.numeric(as.character(housingvaluation$PavedDrive))

housingvaluation$Slope <- factor(housingvaluation$Slope, levels=c("Sev","Mod","Gtl"), 
labels=c(2,1,0))
housingvaluation$Slope <- as.numeric(as.character(housingvaluation$Slope))

#Part B - Question 2


#question 2: a. Calculate the summary statistics: mean, median, max and standard deviation for each of the continuous variables, and count for each categorical variable. 

continuous_var <- c("LotArea", "TotalBSF", "LivingArea", "SalePrice", "OpenPorchSF", "LowQualFinSF","PoolArea", "GarageCars")


summary_Con_var <- summary(housingvaluation[, continuous_var])

# Standard Deviation
sd_results <- sapply(housingvaluation[, c("LotArea", "TotalBSF", "LivingArea", "SalePrice", "OpenPorchSF", "LowQualFinSF","PoolArea", "GarageCars")], 
                     function(x) sd(x, na.rm = TRUE))

#Count of each catergorical variables
categorical_var <- subset(housingvaluation, select = -c(LotArea, TotalBSF, LivingArea, SalePrice, OpenPorchSF, LowQualFinSF, PoolArea, GarageCars))

frequency_tables <- lapply(categorical_var, table)

frequency_df <- do.call(rbind, lapply(names(frequency_tables), function(var) {
  data.frame(
    Variable = var,
    Category = names(frequency_tables[[var]]),
    Frequency = as.vector(frequency_tables[[var]])
  )
}))

write.csv(frequency_df, "categorical_frequency_table.csv", row.names = FALSE)



#Check for extreme values

par(mfrow = c(3, 5), mar = c(4, 4, 2, 1))

for (var in continuous_var) {
  boxplot(housingvaluation[[var]], 
          main = var, 
          ylab = var,
          col = "lightblue",
          outline = TRUE)}
par(mfrow = c(1, 1))

#Part B - Question 3


#Histogram


housingvaluation %>%
    select(all_of(continuous_var)) %>%
    gather(key = "variable", value = "value") %>%
    ggplot(aes(x = value)) +
    facet_wrap(~ variable, scales = "free") +
    geom_histogram()


par(mfrow=c(3,3))
hist(housingvaluation$LotArea, breaks = 50, col="orange", main = "LotArea")
hist(housingvaluation$LivingArea, breaks = 50, col="orange", main = "LivingArea")
hist(housingvaluation$TotalBSF, breaks = 50, col="orange", main = "TotalBSF")
hist(housingvaluation$SalePrice, breaks = 50, col="orange", main = "SalePrice")
hist(housingvaluation$LowQualFinSF, breaks = 50, col="orange", main = "LowQualFinSF")
hist(housingvaluation$PoolArea, breaks = 50, col="orange", main = "PoolArea")
hist(housingvaluation$OpenPorchSF, breaks = 50, col="orange", main = "OpenPorchSF")
hist(housingvaluation$GarageCars, breaks = 50, col="orange", main = "GarageCars")


#Outlier

find_outliers <- function(x) {
  x <- x[!is.na(x)]  
  if (length(x) == 0) return(numeric(0)) 
  Q1 <- quantile(x, 0.25)
  Q3 <- quantile(x, 0.75)
  IQR <- Q3 - Q1
  lower_bound <- Q1 - 1.5 * IQR
  upper_bound <- Q3 + 1.5 * IQR
  return(x[x < lower_bound | x > upper_bound])
}

outliers <- lapply(housingvaluation[continuous_var], function(x) {
  tryCatch(
    find_outliers(x),
    error = function(e) {
      warning(paste("Error processing variable:", deparse(substitute(x))))
      return(NULL)
    }
  )
})
  
print(outliers)

#Part B - Question 4

#1 Identify missing value
missing_values <- colSums(is.na(housingvaluation))
variables_with_missing <- names(missing_values[missing_values > 0])

missing_percentages <- colMeans(is.na(housingvaluation)) * 100
print(missing_percentages[missing_percentages > 0])

summary(housingvaluation)

# Remove missing values
Remove_missing_value <- housingvaluation

all.deleted <- Remove_missing_value[complete.cases(Remove_missing_value),]


mean(all.deleted$LivingArea, na.rm = TRUE)
mean(housingvaluation$LivingArea, na.rm = TRUE)

mean(all.deleted$YearBuilt, na.rm = TRUE)
mean(housingvaluation$YearBuilt, na.rm = TRUE)

png("correlation_plot_rmmv.png", width=2500, height=2500, res=150)
pairs.panels(Replace_with_mean, col="red")
dev.off()


plot(density(all.deleted$LivingArea), col="red", 
 main="LivingArea Original (Blue) vs Transformed (Red)") 
lines(density(Remove_missing_value$LivingArea, na.rm = TRUE), col="blue")

plot(density(all.deleted$YearBuilt), col="red", 
 main="YearBuilt Original (Blue) vs Transformed (Red)") 
lines(density(Remove_missing_value$YearBuilt, na.rm = TRUE), col="blue")

#Replace with mean


Replace_with_mean <- housingvaluation

summary(Replace_with_mean)

Replace_with_mean$YearBuilt[is.na(Replace_with_mean$YearBuilt)] <- mean(Replace_with_mean$YearBuilt, na.rm = TRUE)
mean(Replace_with_mean$YearBuilt, na.rm = TRUE)

Replace_with_mean$LivingArea[is.na(Replace_with_mean$LivingArea)] <- mean(Replace_with_mean$LivingArea, na.rm = TRUE)
mean(Replace_with_mean$LivingArea, na.rm = TRUE)

png("correlation_plot_rpwm.png", width=2500, height=2500, res=150)
pairs.panels(Replace_with_mean, col="red")
dev.off()


plot(density(Replace_with_mean$YearBuilt), col="red",
 main="YearBuilt Original (Blue) vs Transformed (Red)") 
lines(density(housingvaluation$YearBuilt, na.rm = TRUE), col="blue")

plot(density(Replace_with_mean$LivingArea), col="red",
 main="LivingArea Original (Blue) vs Transformed (Red)") 
lines(density(housingvaluation$LivingArea, na.rm = TRUE), col="blue")


#Replace With Zero

MV_zero <- housingvaluation

MV_zero[is.na(MV_zero)] <- 0

mean(MV_zero$YearBuilt, na.rm = TRUE)
mean(housingvaluation$YearBuilt, na.rm = TRUE)
mean(MV_zero$LivingArea, na.rm = TRUE)
mean(housingvaluation$LivingArea, na.rm = TRUE)

png("correlation_plot.png", width=2500, height=2500, res=150)
pairs.panels(MV_zero, col="red")
dev.off()



plot(density(MV_zero$YearBuilt), col="red", 
 main="YearBuilt Original (Blue) vs Transformed (Red)") 
lines(density(housingvaluation$YearBuilt, na.rm = TRUE), col="blue")

plot(density(MV_zero$LivingArea), col="red", 
 main="LivingArea Original (Blue) vs Transformed (Red)") 
lines(density(housingvaluation$LivingArea, na.rm = TRUE), col="blue")
#final dataset

housingvaluation <- housingvaluation[, !names(housingvaluation) %in% c("Id")]

housingvaluation_complete <- housingvaluation[complete.cases(housingvaluation),]

summary(housingvaluation_complete)

#Part B - Question 5

names(housingdataset)[highlyCorr]
 [1] "OverallQuality"           "LivingArea"               "YearBuilt"               
 [4] "GarageCars"               "FullBath"                 "TotalRmsAbvGrd"          
 [7] "Attachedtohome_garage"    "KitchenAbvGr"             "Dwellclass_Single_Family"
[10] "LotConfig_Inside"         "Slope"                    "Utilities_NoSeWa"        


selected_attr <- housingvaluation_complete$SalePrice
par(mfrow=c(1,2))
hist(selected_attr, col="orange", main="Histogram")
plot(density(selected_attr, na.rm=TRUE), main="Density")


#Distribution of selected variables against the target variable
Selected_vars <- subset(housingdataset, select = -c(KitchenAbvGr, Utilities_NoSeWa, Attachedtohome_garage, MoSold, YrSold, GarageCars))

Selected_vars$SalePrice <- target_var

#Distribution of continous vars with target var

continuous_vars2 <- c("LotArea", "TotalBSF", "LivingArea", "OpenPorchSF", "LowQualFinSF", "PoolArea")

par(mfrow = c(2, 3))
plot_list <- list()

for (var in continuous_vars2) {
  p <- ggplot(Selected_vars, aes_string(x = var, y = "SalePrice")) +
    geom_point(alpha = 0.5, color = "steelblue") +
    geom_smooth(method = "lm", color = "red", se = FALSE) +
    labs(x = var, y = "Sale Price", title = paste("Sale Price vs", var)) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"),
          axis.title = element_text(face = "bold"),
          axis.text = element_text(size = 8))
  
  plot_list[[var]] <- p
}
grid.arrange(grobs = plot_list, ncol = 3)


#Distribution of categorical vars with target var

categorical_vars2 <- Selected_vars %>%
  select(-c(LotArea, TotalBSF, LivingArea, OpenPorchSF, LowQualFinSF, PoolArea, SalePrice))


plot_data <- categorical_vars2 %>%
  mutate(SalePrice = Selected_vars$SalePrice) %>%
  pivot_longer(cols = -SalePrice, names_to = "Variable", values_to = "Category") %>%
  group_by(Variable, Category) %>%
  summarise(MeanSalePrice = mean(SalePrice, na.rm = TRUE), .groups = 'drop')

plot_list <- lapply(unique(plot_data$Variable), function(var) {
  ggplot(plot_data[plot_data$Variable == var,], aes(x = Category, y = MeanSalePrice)) +
    geom_bar(stat = "identity", fill = "skyblue") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 6),
          axis.text.y = element_text(size = 6),
          plot.title = element_text(size = 8),
          plot.margin = unit(c(0.1, 0.1, 0.1, 0.1), "cm")) +
    labs(title = var, x = NULL, y = NULL) +
    scale_y_continuous(labels = scales::dollar_format(scale = 1e-3, suffix = "K"))
})

n_plots <- length(plot_list)
n_cols <- ceiling(sqrt(n_plots))
n_rows <- ceiling(n_plots / n_cols)

cat_dis <- grid.arrange(
  grobs = plot_list,
  ncol = n_cols,
  nrow = n_rows,
  top = "Distribution of Categorical Variables vs SalePrice"
)
#Test for skewness

housingdataset %>%
  select(all_of(continuous_vars2)) %>%
  gather(key = "variable", value = "value") %>%
  ggplot(aes(x = value)) +
  facet_wrap(~ variable, scales = "free") +
  geom_histogram()

categorical_var3 <- colnames(categorical_vars2)

housingdataset %>%
  select(all_of(categorical_var3)) %>%
  gather(key = "variable", value = "value") %>%
  ggplot(aes(x = value)) +
  facet_wrap(~ variable, scales = "free") +
  geom_bar()
#Tranform to normal distribution

right_skewcols <- c("LivingArea", "OpenPorchSF", "TotalBSF", "LotArea")

housingdataset[right_skewcols] <- lapply(housingdataset[right_skewcols], function(x) {
  x[x <= 0] <- 0.01
  log(x)
})


housingdataset %>%
  select(all_of(continuous_vars2)) %>%
  gather(key = "variable", value = "value") %>%
  ggplot(aes(x = value)) +
  facet_wrap(~ variable, scales = "free") +
  geom_histogram()

#Part C- question 1

summary(hmodel2)$coefficients
                                  Estimate   Std. Error     t value     Pr(>|t|)
(Intercept)                  -1.833821e+06 187818.60432 -9.76378708 1.718300e-21
LotArea                       2.486928e+04   3904.80433  6.36889185 3.007553e-10
LotShape                      2.527157e+03   2517.55135  1.00381539 3.157324e-01
LandContour                   1.522128e+02   2608.27264  0.05835769 9.534764e-01
Slope                         7.718414e+03   5734.40777  1.34598279 1.786407e-01
OverallQuality                2.004424e+04   1634.30220 12.26470852 3.956659e-32
OverallCondition              5.575092e+03   1442.22800  3.86561101 1.186240e-04
YearBuilt                     5.495736e+02     81.42688  6.74929020 2.631501e-11
ExteriorCondition            -9.264129e+02   3981.01178 -0.23270791 8.160402e-01
BasementCondition            -4.717354e+03   4424.54518 -1.06617819 2.866237e-01
TotalBSF                      2.525382e+03   1063.61873  2.37432998 1.778582e-02
CentralAir                   -9.180487e+03   6083.25797 -1.50913991 1.316075e-01
LowQualFinSF                 -1.778281e+01     22.74613 -0.78179519 4.345368e-01
LivingArea                    5.883810e+04   9466.49113  6.21540748 7.761564e-10
FullBath                     -1.894774e+02   3629.51900 -0.05220454 9.583771e-01
HalfBath                     -5.376196e+03   3016.16044 -1.78246345 7.500446e-02
BedroomAbvGr                 -1.128418e+04   2204.15643 -5.11950156 3.732967e-07
KitchenQuality                1.960675e+04   2701.32514  7.25819844 8.359075e-13
TotalRmsAbvGrd                7.030814e+03   1599.20751  4.39643625 1.229220e-05
Fireplaces                    6.948801e+03   2265.97287  3.06658620 2.228683e-03
PavedDrive                    2.103123e+02   2839.80703  0.07405866 9.409799e-01
PoolArea                      3.340128e+01     28.84393  1.15800029 2.471654e-01
OpenPorchSF                  -2.265520e+02    331.81891 -0.68275806 4.949322e-01
Utilities_AllPub              6.545862e+04  39148.75661  1.67204843 9.485591e-02
LotConfig_Corner             -2.833160e+03   3336.10807 -0.84924113 3.959688e-01
LotConfig_CulDSac             7.578925e+03   5519.00873  1.37324019 1.700134e-01
LotConfig_FR2                -4.029876e+03   6948.49180 -0.57996406 5.620813e-01
LotConfig_FR3                -9.110845e+03  21840.81657 -0.41714762 6.766681e-01
Dwellclass_Single_Family      4.519468e+03   8942.75442  0.50537765 6.134151e-01
Dwellclass_Two_Family        -6.463472e+02  13161.53489 -0.04910880 9.608433e-01
Dwellclass_Duplex             5.069052e+03  11440.51551  0.44307898 6.578131e-01
Dwellclass_Townhouse_EndUnit  6.006218e+02   8655.96190  0.06938822 9.446957e-01
Twotypes_garage               2.112669e+03  26843.59405  0.07870291 9.372861e-01
Basement_garage               1.870783e+03  11068.23606  0.16902273 8.658160e-01
Buildin_garage                8.084745e+03   5608.13870  1.44160933 1.497540e-01
Carport_garage               -1.296701e+04  15034.96768 -0.86245667 3.886618e-01
Detachedfromhome_garage       2.912890e+03   3356.42972  0.86785370 3.857015e-01
plot3 <- test.set3 %>% 
  ggplot(aes(SalePrice,predicted.SalePrice)) + 
  geom_point(alpha=0.5) + 
  stat_smooth(aes(colour='red')) + 
  xlab('Actual value of SalePrice') + 
  ylab('Predicted value of SalePrice')+ 
  theme_bw()
ggplotly(plot3)
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'

#Decision Tree

dcthousing <- housingdataset_selected1
Error: object 'housingdataset_selected1' not found
dtree$variable.importance
  OverallQuality       LivingArea         TotalBSF   KitchenQuality        YearBuilt   TotalRmsAbvGrd 
    3.943247e+12     1.054748e+12     1.043928e+12     1.038985e+12     7.239169e+11     4.288177e+11 
    BedroomAbvGr          LotArea         HalfBath         FullBath       Fireplaces   Buildin_garage 
    2.170179e+11     1.509278e+11     1.429624e+11     1.346425e+11     4.652120e+10     1.924287e+10 
LotConfig_Corner 
    1.635907e+10 

print(paste("Root Mean Square Error: ", dct_rmse))
[1] "Root Mean Square Error:  43645.6040879741"
print(pruned.dtree)
n= 954 

node), split, n, deviance, yval
      * denotes terminal node

 1) root 954 6.017664e+12 181808.0  
   2) OverallQuality< 7.5 801 1.867541e+12 157862.2  
     4) OverallQuality< 6.5 592 8.130738e+11 140674.1  
       8) LivingArea< 7.235619 369 3.024860e+11 125960.4  
        16) TotalBSF< 6.915227 242 1.488286e+11 114974.5 *
        17) TotalBSF>=6.915227 127 6.879663e+10 146894.1 *
       9) LivingArea>=7.235619 223 2.985157e+11 165020.8 *
     5) OverallQuality>=6.5 209 3.841739e+11 206548.1  
      10) LivingArea< 7.507689 136 1.282820e+11 189035.2 *
      11) LivingArea>=7.507689 73 1.364708e+11 239175.0 *
   3) OverallQuality>=7.5 153 1.286291e+12 307171.2  
     6) OverallQuality< 8.5 111 4.357182e+11 275362.6  
      12) LivingArea< 7.564236 64 1.461172e+11 245779.4 *
      13) LivingArea>=7.564236 47 1.573209e+11 315646.1 *
     7) OverallQuality>=8.5 42 4.414506e+11 391236.6  
      14) LivingArea< 7.610357 19 1.950673e+10 332807.7 *
      15) LivingArea>=7.610357 23 3.034949e+11 439504.0 *

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMS1QcmVkaWN0aXZlIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KI0xpYnJhcnkNCmBgYHtyfQ0KDQpzYXZlLmltYWdlKGZpbGU9Im15UHJlZGljdGl2ZWFzbTEuUkRhdGEiKQ0KbG9hZCgibXlQcmVkaWN0aXZlYXNtMS5SRGF0YSIpDQoNCg0KbGlicmFyeShwc3ljaCkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KEFtZWxpYSkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHB1cnJyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQpsaWJyYXJ5KHJwYXJ0KQ0KbGlicmFyeShycGFydC5wbG90KQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCg0KDQoNCg0KDQpgYGANCg0KI1BhcnQgQi1RdWVzdGlvbiAxDQpgYGB7cn0NCg0KaG91c2luZ3ZhbHVhdGlvbiA8LSByZWFkLmNzdigiSG91c2luZ1ZhbHVhdGlvbi5jc3YiKQ0KDQpzdW1tYXJ5KGhvdXNpbmd2YWx1YXRpb24pDQpWaWV3KGhvdXNpbmd2YWx1YXRpb24pDQpzdHIoaG91c2luZ3ZhbHVhdGlvbikNCg0Kc3VtbWFyeShob3VzaW5ndmFsdWF0aW9uJExpdmluZ0FyZWEpDQpgYGANCg0KI1BhcnRCLVF1ZXN0aW9uIDIgJiAzDQpgYGB7cn0NCiMgVHJhbmZvcm0gbm9taW5hbCB2YXJpYWJsZSBpbiB0byBudW1lcmljYWwNCg0KaG91c2luZ3ZhbHVhdGlvbiRVdGlsaXRpZXNfQWxsUHViIDwtIGFzLm51bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRVdGlsaXRpZXMgPT0gIkFsbFB1YiIpDQpob3VzaW5ndmFsdWF0aW9uJFV0aWxpdGllc19Ob1NlV2EgPC0gYXMubnVtZXJpYyhob3VzaW5ndmFsdWF0aW9uJFV0aWxpdGllcyA9PSAiTm9TZVdhIikNCg0KaG91c2luZ3ZhbHVhdGlvbiA8LSBob3VzaW5ndmFsdWF0aW9uWywgIW5hbWVzKGhvdXNpbmd2YWx1YXRpb24pICVpbiUgYygiVXRpbGl0aWVzIildDQoNCg0KaG91c2luZ3ZhbHVhdGlvbiRMb3RDb25maWdfQ29ybmVyIDwtIGFzLm51bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRMb3RDb25maWcgPT0gIkNvcm5lciIpDQpob3VzaW5ndmFsdWF0aW9uJExvdENvbmZpZ19DdWxEU2FjIDwtIGFzLm51bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRMb3RDb25maWcgPT0gIkN1bERTYWMiKQ0KaG91c2luZ3ZhbHVhdGlvbiRMb3RDb25maWdfRlIyIDwtIGFzLm51bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRMb3RDb25maWcgPT0gIkZSMiIpDQpob3VzaW5ndmFsdWF0aW9uJExvdENvbmZpZ19GUjMgPC0gYXMubnVtZXJpYyhob3VzaW5ndmFsdWF0aW9uJExvdENvbmZpZyA9PSAiRlIzIikNCmhvdXNpbmd2YWx1YXRpb24kTG90Q29uZmlnX0luc2lkZSA8LSBhcy5udW1lcmljKGhvdXNpbmd2YWx1YXRpb24kTG90Q29uZmlnID09ICJJbnNpZGUiKQ0KDQpob3VzaW5ndmFsdWF0aW9uIDwtIGhvdXNpbmd2YWx1YXRpb25bLCAhbmFtZXMoaG91c2luZ3ZhbHVhdGlvbikgJWluJSBjKCJMb3RDb25maWciKV0NCg0KaG91c2luZ3ZhbHVhdGlvbiREd2VsbGNsYXNzX1NpbmdsZV9GYW1pbHkgPC0gYXMubnVtZXJpYyhob3VzaW5ndmFsdWF0aW9uJER3ZWxsQ2xhc3MgPT0gIjFGYW0iKQ0KaG91c2luZ3ZhbHVhdGlvbiREd2VsbGNsYXNzX1R3b19GYW1pbHkgPC0gYXMubnVtZXJpYyhob3VzaW5ndmFsdWF0aW9uJER3ZWxsQ2xhc3MgPT0gIjJmbUNvbiIpDQpob3VzaW5ndmFsdWF0aW9uJER3ZWxsY2xhc3NfRHVwbGV4IDwtIGFzLm51bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiREd2VsbENsYXNzID09ICJEdXBsZXgiKQ0KaG91c2luZ3ZhbHVhdGlvbiREd2VsbGNsYXNzX1Rvd25ob3VzZV9FbmRVbml0IDwtIGFzLm51bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiREd2VsbENsYXNzID09ICJUd25oc0UiKQ0KaG91c2luZ3ZhbHVhdGlvbiREd2VsbGNsYXNzX1Rvd25ob3VzZV9JbnNpZGVVbml0ZSA8LSBhcy5udW1lcmljKGhvdXNpbmd2YWx1YXRpb24kRHdlbGxDbGFzcyA9PSAiVHduaHMiKQ0KDQpob3VzaW5ndmFsdWF0aW9uIDwtIGhvdXNpbmd2YWx1YXRpb25bLCAhbmFtZXMoaG91c2luZ3ZhbHVhdGlvbikgJWluJSBjKCJEd2VsbENsYXNzIildDQpgYGANCg0KDQpgYGB7cn0NCg0KI0hhbmRsZSBOQSB2YWx1ZXMgb2YgR3JhcmFnZVR5cGUgdmFyaWFibGUNCg0KTkFfbnVtZXJpYyA8LSBmdW5jdGlvbih4LCB2YWx1ZSkgew0KICBpZmVsc2UoaXMubmEoeCksIDAsIGFzLm51bWVyaWMoeCA9PSB2YWx1ZSkpDQp9DQoNCmhvdXNpbmd2YWx1YXRpb24kVHdvdHlwZXNfZ2FyYWdlIDwtIE5BX251bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VUeXBlLCAiMlR5cGVzIikNCmhvdXNpbmd2YWx1YXRpb24kQXR0YWNoZWR0b2hvbWVfZ2FyYWdlIDwtIE5BX251bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VUeXBlLCAiQXR0Y2hkIikNCmhvdXNpbmd2YWx1YXRpb24kQmFzZW1lbnRfZ2FyYWdlIDwtIE5BX251bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VUeXBlLCAiQmFzbWVudCIpDQpob3VzaW5ndmFsdWF0aW9uJEJ1aWxkaW5fZ2FyYWdlIDwtIE5BX251bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VUeXBlLCAiQnVpbHRJbiIpDQpob3VzaW5ndmFsdWF0aW9uJENhcnBvcnRfZ2FyYWdlIDwtIE5BX251bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VUeXBlLCAiQ2FyUG9ydCIpDQpob3VzaW5ndmFsdWF0aW9uJERldGFjaGVkZnJvbWhvbWVfZ2FyYWdlIDwtIE5BX251bWVyaWMoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VUeXBlLCAiRGV0Y2hkIikNCg0KDQpob3VzaW5ndmFsdWF0aW9uIDwtIGhvdXNpbmd2YWx1YXRpb25bLCAhbmFtZXMoaG91c2luZ3ZhbHVhdGlvbikgJWluJSBjKCJHYXJhZ2VUeXBlIildDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI1RyYW5mb3JtIG9yZGluYWwgdmFyaWJsZXMgaW50byBudW1lcmljYWwNCg0KDQpob3VzaW5ndmFsdWF0aW9uJEV4dGVyaW9yQ29uZGl0aW9uIDwtIGZhY3Rvcihob3VzaW5ndmFsdWF0aW9uJEV4dGVyaW9yQ29uZGl0aW9uLCBsZXZlbHM9YygiR2QiLCJUQSIsIkZhIiksIGxhYmVscz1jKDIsMSwwKSkNCmhvdXNpbmd2YWx1YXRpb24kRXh0ZXJpb3JDb25kaXRpb24gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoaG91c2luZ3ZhbHVhdGlvbiRFeHRlcmlvckNvbmRpdGlvbikpDQoNCmhvdXNpbmd2YWx1YXRpb24kQ2VudHJhbEFpciA8LSBmYWN0b3IoaG91c2luZ3ZhbHVhdGlvbiRDZW50cmFsQWlyLCBsZXZlbHM9YygiTiIsIlkiKSwgDQpsYWJlbHM9YygwLDEpKQ0KaG91c2luZ3ZhbHVhdGlvbiRDZW50cmFsQWlyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGhvdXNpbmd2YWx1YXRpb24kQ2VudHJhbEFpcikpDQoNCmhvdXNpbmd2YWx1YXRpb24kQmFzZW1lbnRDb25kaXRpb24gPC0gIGZhY3Rvcihob3VzaW5ndmFsdWF0aW9uJEJhc2VtZW50Q29uZGl0aW9uLCBsZXZlbHM9YygiR2QiLCJUQSIsIkZhIiwiTkIiKSwgDQpsYWJlbHM9YygzLDIsMSwwKSkNCmhvdXNpbmd2YWx1YXRpb24kQmFzZW1lbnRDb25kaXRpb24gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoaG91c2luZ3ZhbHVhdGlvbiRCYXNlbWVudENvbmRpdGlvbikpDQoNCmhvdXNpbmd2YWx1YXRpb24kS2l0Y2hlblF1YWxpdHkgPC0gZmFjdG9yKGhvdXNpbmd2YWx1YXRpb24kS2l0Y2hlblF1YWxpdHksIGxldmVscz1jKCJFeCIsIkdkIiwiVEEiLCJGYSIpLCANCmxhYmVscz1jKDMsMiwxLDApKQ0KaG91c2luZ3ZhbHVhdGlvbiRLaXRjaGVuUXVhbGl0eSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihob3VzaW5ndmFsdWF0aW9uJEtpdGNoZW5RdWFsaXR5KSkNCg0KaG91c2luZ3ZhbHVhdGlvbiRMYW5kQ29udG91ciA8LSBmYWN0b3IoaG91c2luZ3ZhbHVhdGlvbiRMYW5kQ29udG91ciwgbGV2ZWxzPWMoIkxvdyIsIkhMUyIsIkJuayIsIkx2bCIpLCANCmxhYmVscz1jKDMsMiwxLDApKQ0KaG91c2luZ3ZhbHVhdGlvbiRMYW5kQ29udG91ciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihob3VzaW5ndmFsdWF0aW9uJExhbmRDb250b3VyKSkNCg0KaG91c2luZ3ZhbHVhdGlvbiRQYXZlZERyaXZlIDwtIGZhY3Rvcihob3VzaW5ndmFsdWF0aW9uJFBhdmVkRHJpdmUsIGxldmVscz1jKCJZIiwiUCIsIk4iKSwgDQpsYWJlbHM9YygyLDEsMCkpDQpob3VzaW5ndmFsdWF0aW9uJFBhdmVkRHJpdmUgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoaG91c2luZ3ZhbHVhdGlvbiRQYXZlZERyaXZlKSkNCg0KaG91c2luZ3ZhbHVhdGlvbiRTbG9wZSA8LSBmYWN0b3IoaG91c2luZ3ZhbHVhdGlvbiRTbG9wZSwgbGV2ZWxzPWMoIlNldiIsIk1vZCIsIkd0bCIpLCANCmxhYmVscz1jKDIsMSwwKSkNCmhvdXNpbmd2YWx1YXRpb24kU2xvcGUgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoaG91c2luZ3ZhbHVhdGlvbiRTbG9wZSkpDQoNCg0KDQpgYGANCg0KI1BhcnQgQiAtIFF1ZXN0aW9uIDINCmBgYHtyfQ0KDQojcXVlc3Rpb24gMjogYS4gQ2FsY3VsYXRlIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3M6IG1lYW4sIG1lZGlhbiwgbWF4IGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggb2YgdGhlIGNvbnRpbnVvdXMgdmFyaWFibGVzLCBhbmQgY291bnQgZm9yIGVhY2ggY2F0ZWdvcmljYWwgdmFyaWFibGUuIA0KDQpjb250aW51b3VzX3ZhciA8LSBjKCJMb3RBcmVhIiwgIlRvdGFsQlNGIiwgIkxpdmluZ0FyZWEiLCAiU2FsZVByaWNlIiwgIk9wZW5Qb3JjaFNGIiwgIkxvd1F1YWxGaW5TRiIsIlBvb2xBcmVhIiwgIkdhcmFnZUNhcnMiKQ0KDQoNCnN1bW1hcnlfQ29uX3ZhciA8LSBzdW1tYXJ5KGhvdXNpbmd2YWx1YXRpb25bLCBjb250aW51b3VzX3Zhcl0pDQoNCiMgU3RhbmRhcmQgRGV2aWF0aW9uDQpzZF9yZXN1bHRzIDwtIHNhcHBseShob3VzaW5ndmFsdWF0aW9uWywgYygiTG90QXJlYSIsICJUb3RhbEJTRiIsICJMaXZpbmdBcmVhIiwgIlNhbGVQcmljZSIsICJPcGVuUG9yY2hTRiIsICJMb3dRdWFsRmluU0YiLCJQb29sQXJlYSIsICJHYXJhZ2VDYXJzIildLCANCiAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHNkKHgsIG5hLnJtID0gVFJVRSkpDQoNCiNDb3VudCBvZiBlYWNoIGNhdGVyZ29yaWNhbCB2YXJpYWJsZXMNCmNhdGVnb3JpY2FsX3ZhciA8LSBzdWJzZXQoaG91c2luZ3ZhbHVhdGlvbiwgc2VsZWN0ID0gLWMoTG90QXJlYSwgVG90YWxCU0YsIExpdmluZ0FyZWEsIFNhbGVQcmljZSwgT3BlblBvcmNoU0YsIExvd1F1YWxGaW5TRiwgUG9vbEFyZWEsIEdhcmFnZUNhcnMpKQ0KDQpmcmVxdWVuY3lfdGFibGVzIDwtIGxhcHBseShjYXRlZ29yaWNhbF92YXIsIHRhYmxlKQ0KDQpmcmVxdWVuY3lfZGYgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KG5hbWVzKGZyZXF1ZW5jeV90YWJsZXMpLCBmdW5jdGlvbih2YXIpIHsNCiAgZGF0YS5mcmFtZSgNCiAgICBWYXJpYWJsZSA9IHZhciwNCiAgICBDYXRlZ29yeSA9IG5hbWVzKGZyZXF1ZW5jeV90YWJsZXNbW3Zhcl1dKSwNCiAgICBGcmVxdWVuY3kgPSBhcy52ZWN0b3IoZnJlcXVlbmN5X3RhYmxlc1tbdmFyXV0pDQogICkNCn0pKQ0KDQp3cml0ZS5jc3YoZnJlcXVlbmN5X2RmLCAiY2F0ZWdvcmljYWxfZnJlcXVlbmN5X3RhYmxlLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQoNCg0KI0NoZWNrIGZvciBleHRyZW1lIHZhbHVlcw0KDQpwYXIobWZyb3cgPSBjKDMsIDUpLCBtYXIgPSBjKDQsIDQsIDIsIDEpKQ0KDQpmb3IgKHZhciBpbiBjb250aW51b3VzX3Zhcikgew0KICBib3hwbG90KGhvdXNpbmd2YWx1YXRpb25bW3Zhcl1dLCANCiAgICAgICAgICBtYWluID0gdmFyLCANCiAgICAgICAgICB5bGFiID0gdmFyLA0KICAgICAgICAgIGNvbCA9ICJsaWdodGJsdWUiLA0KICAgICAgICAgIG91dGxpbmUgPSBUUlVFKX0NCnBhcihtZnJvdyA9IGMoMSwgMSkpDQoNCg0KDQpgYGANCg0KDQojUGFydCBCIC0gUXVlc3Rpb24gMw0KYGBge3J9DQoNCiNIaXN0b2dyYW0NCg0KDQpob3VzaW5ndmFsdWF0aW9uICU+JQ0KICAgIHNlbGVjdChhbGxfb2YoY29udGludW91c192YXIpKSAlPiUNCiAgICBnYXRoZXIoa2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSkpICsNCiAgICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIGdlb21faGlzdG9ncmFtKCkNCg0KDQpwYXIobWZyb3c9YygzLDMpKQ0KaGlzdChob3VzaW5ndmFsdWF0aW9uJExvdEFyZWEsIGJyZWFrcyA9IDUwLCBjb2w9Im9yYW5nZSIsIG1haW4gPSAiTG90QXJlYSIpDQpoaXN0KGhvdXNpbmd2YWx1YXRpb24kTGl2aW5nQXJlYSwgYnJlYWtzID0gNTAsIGNvbD0ib3JhbmdlIiwgbWFpbiA9ICJMaXZpbmdBcmVhIikNCmhpc3QoaG91c2luZ3ZhbHVhdGlvbiRUb3RhbEJTRiwgYnJlYWtzID0gNTAsIGNvbD0ib3JhbmdlIiwgbWFpbiA9ICJUb3RhbEJTRiIpDQpoaXN0KGhvdXNpbmd2YWx1YXRpb24kU2FsZVByaWNlLCBicmVha3MgPSA1MCwgY29sPSJvcmFuZ2UiLCBtYWluID0gIlNhbGVQcmljZSIpDQpoaXN0KGhvdXNpbmd2YWx1YXRpb24kTG93UXVhbEZpblNGLCBicmVha3MgPSA1MCwgY29sPSJvcmFuZ2UiLCBtYWluID0gIkxvd1F1YWxGaW5TRiIpDQpoaXN0KGhvdXNpbmd2YWx1YXRpb24kUG9vbEFyZWEsIGJyZWFrcyA9IDUwLCBjb2w9Im9yYW5nZSIsIG1haW4gPSAiUG9vbEFyZWEiKQ0KaGlzdChob3VzaW5ndmFsdWF0aW9uJE9wZW5Qb3JjaFNGLCBicmVha3MgPSA1MCwgY29sPSJvcmFuZ2UiLCBtYWluID0gIk9wZW5Qb3JjaFNGIikNCmhpc3QoaG91c2luZ3ZhbHVhdGlvbiRHYXJhZ2VDYXJzLCBicmVha3MgPSA1MCwgY29sPSJvcmFuZ2UiLCBtYWluID0gIkdhcmFnZUNhcnMiKQ0KDQoNCiNPdXRsaWVyDQoNCmZpbmRfb3V0bGllcnMgPC0gZnVuY3Rpb24oeCkgew0KICB4IDwtIHhbIWlzLm5hKHgpXSAgDQogIGlmIChsZW5ndGgoeCkgPT0gMCkgcmV0dXJuKG51bWVyaWMoMCkpIA0KICBRMSA8LSBxdWFudGlsZSh4LCAwLjI1KQ0KICBRMyA8LSBxdWFudGlsZSh4LCAwLjc1KQ0KICBJUVIgPC0gUTMgLSBRMQ0KICBsb3dlcl9ib3VuZCA8LSBRMSAtIDEuNSAqIElRUg0KICB1cHBlcl9ib3VuZCA8LSBRMyArIDEuNSAqIElRUg0KICByZXR1cm4oeFt4IDwgbG93ZXJfYm91bmQgfCB4ID4gdXBwZXJfYm91bmRdKQ0KfQ0KDQpvdXRsaWVycyA8LSBsYXBwbHkoaG91c2luZ3ZhbHVhdGlvbltjb250aW51b3VzX3Zhcl0sIGZ1bmN0aW9uKHgpIHsNCiAgdHJ5Q2F0Y2goDQogICAgZmluZF9vdXRsaWVycyh4KSwNCiAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsNCiAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIHByb2Nlc3NpbmcgdmFyaWFibGU6IiwgZGVwYXJzZShzdWJzdGl0dXRlKHgpKSkpDQogICAgICByZXR1cm4oTlVMTCkNCiAgICB9DQogICkNCn0pDQogIA0KcHJpbnQob3V0bGllcnMpDQoNCmBgYA0KDQoNCg0KI1BhcnQgQiAtIFF1ZXN0aW9uIDQNCmBgYHtyfQ0KIzEgSWRlbnRpZnkgbWlzc2luZyB2YWx1ZQ0KbWlzc2luZ192YWx1ZXMgPC0gY29sU3Vtcyhpcy5uYShob3VzaW5ndmFsdWF0aW9uKSkNCnZhcmlhYmxlc193aXRoX21pc3NpbmcgPC0gbmFtZXMobWlzc2luZ192YWx1ZXNbbWlzc2luZ192YWx1ZXMgPiAwXSkNCg0KbWlzc2luZ19wZXJjZW50YWdlcyA8LSBjb2xNZWFucyhpcy5uYShob3VzaW5ndmFsdWF0aW9uKSkgKiAxMDANCnByaW50KG1pc3NpbmdfcGVyY2VudGFnZXNbbWlzc2luZ19wZXJjZW50YWdlcyA+IDBdKQ0KDQpzdW1tYXJ5KGhvdXNpbmd2YWx1YXRpb24pDQoNCiMgUmVtb3ZlIG1pc3NpbmcgdmFsdWVzDQpSZW1vdmVfbWlzc2luZ192YWx1ZSA8LSBob3VzaW5ndmFsdWF0aW9uDQoNCmFsbC5kZWxldGVkIDwtIFJlbW92ZV9taXNzaW5nX3ZhbHVlW2NvbXBsZXRlLmNhc2VzKFJlbW92ZV9taXNzaW5nX3ZhbHVlKSxdDQoNCg0KbWVhbihhbGwuZGVsZXRlZCRMaXZpbmdBcmVhLCBuYS5ybSA9IFRSVUUpDQptZWFuKGhvdXNpbmd2YWx1YXRpb24kTGl2aW5nQXJlYSwgbmEucm0gPSBUUlVFKQ0KDQptZWFuKGFsbC5kZWxldGVkJFllYXJCdWlsdCwgbmEucm0gPSBUUlVFKQ0KbWVhbihob3VzaW5ndmFsdWF0aW9uJFllYXJCdWlsdCwgbmEucm0gPSBUUlVFKQ0KDQpwbmcoImNvcnJlbGF0aW9uX3Bsb3Rfcm1tdi5wbmciLCB3aWR0aD0yNTAwLCBoZWlnaHQ9MjUwMCwgcmVzPTE1MCkNCnBhaXJzLnBhbmVscyhSZXBsYWNlX3dpdGhfbWVhbiwgY29sPSJyZWQiKQ0KZGV2Lm9mZigpDQoNCg0KcGxvdChkZW5zaXR5KGFsbC5kZWxldGVkJExpdmluZ0FyZWEpLCBjb2w9InJlZCIsIA0KIG1haW49IkxpdmluZ0FyZWEgT3JpZ2luYWwgKEJsdWUpIHZzIFRyYW5zZm9ybWVkIChSZWQpIikgDQpsaW5lcyhkZW5zaXR5KFJlbW92ZV9taXNzaW5nX3ZhbHVlJExpdmluZ0FyZWEsIG5hLnJtID0gVFJVRSksIGNvbD0iYmx1ZSIpDQoNCnBsb3QoZGVuc2l0eShhbGwuZGVsZXRlZCRZZWFyQnVpbHQpLCBjb2w9InJlZCIsIA0KIG1haW49IlllYXJCdWlsdCBPcmlnaW5hbCAoQmx1ZSkgdnMgVHJhbnNmb3JtZWQgKFJlZCkiKSANCmxpbmVzKGRlbnNpdHkoUmVtb3ZlX21pc3NpbmdfdmFsdWUkWWVhckJ1aWx0LCBuYS5ybSA9IFRSVUUpLCBjb2w9ImJsdWUiKQ0KDQojUmVwbGFjZSB3aXRoIG1lYW4NCg0KDQpSZXBsYWNlX3dpdGhfbWVhbiA8LSBob3VzaW5ndmFsdWF0aW9uDQoNCnN1bW1hcnkoUmVwbGFjZV93aXRoX21lYW4pDQoNClJlcGxhY2Vfd2l0aF9tZWFuJFllYXJCdWlsdFtpcy5uYShSZXBsYWNlX3dpdGhfbWVhbiRZZWFyQnVpbHQpXSA8LSBtZWFuKFJlcGxhY2Vfd2l0aF9tZWFuJFllYXJCdWlsdCwgbmEucm0gPSBUUlVFKQ0KbWVhbihSZXBsYWNlX3dpdGhfbWVhbiRZZWFyQnVpbHQsIG5hLnJtID0gVFJVRSkNCg0KUmVwbGFjZV93aXRoX21lYW4kTGl2aW5nQXJlYVtpcy5uYShSZXBsYWNlX3dpdGhfbWVhbiRMaXZpbmdBcmVhKV0gPC0gbWVhbihSZXBsYWNlX3dpdGhfbWVhbiRMaXZpbmdBcmVhLCBuYS5ybSA9IFRSVUUpDQptZWFuKFJlcGxhY2Vfd2l0aF9tZWFuJExpdmluZ0FyZWEsIG5hLnJtID0gVFJVRSkNCg0KcG5nKCJjb3JyZWxhdGlvbl9wbG90X3Jwd20ucG5nIiwgd2lkdGg9MjUwMCwgaGVpZ2h0PTI1MDAsIHJlcz0xNTApDQpwYWlycy5wYW5lbHMoUmVwbGFjZV93aXRoX21lYW4sIGNvbD0icmVkIikNCmRldi5vZmYoKQ0KDQoNCnBsb3QoZGVuc2l0eShSZXBsYWNlX3dpdGhfbWVhbiRZZWFyQnVpbHQpLCBjb2w9InJlZCIsDQogbWFpbj0iWWVhckJ1aWx0IE9yaWdpbmFsIChCbHVlKSB2cyBUcmFuc2Zvcm1lZCAoUmVkKSIpIA0KbGluZXMoZGVuc2l0eShob3VzaW5ndmFsdWF0aW9uJFllYXJCdWlsdCwgbmEucm0gPSBUUlVFKSwgY29sPSJibHVlIikNCg0KcGxvdChkZW5zaXR5KFJlcGxhY2Vfd2l0aF9tZWFuJExpdmluZ0FyZWEpLCBjb2w9InJlZCIsDQogbWFpbj0iTGl2aW5nQXJlYSBPcmlnaW5hbCAoQmx1ZSkgdnMgVHJhbnNmb3JtZWQgKFJlZCkiKSANCmxpbmVzKGRlbnNpdHkoaG91c2luZ3ZhbHVhdGlvbiRMaXZpbmdBcmVhLCBuYS5ybSA9IFRSVUUpLCBjb2w9ImJsdWUiKQ0KDQoNCiNSZXBsYWNlIFdpdGggWmVybw0KDQpNVl96ZXJvIDwtIGhvdXNpbmd2YWx1YXRpb24NCg0KTVZfemVyb1tpcy5uYShNVl96ZXJvKV0gPC0gMA0KDQptZWFuKE1WX3plcm8kWWVhckJ1aWx0LCBuYS5ybSA9IFRSVUUpDQptZWFuKGhvdXNpbmd2YWx1YXRpb24kWWVhckJ1aWx0LCBuYS5ybSA9IFRSVUUpDQptZWFuKE1WX3plcm8kTGl2aW5nQXJlYSwgbmEucm0gPSBUUlVFKQ0KbWVhbihob3VzaW5ndmFsdWF0aW9uJExpdmluZ0FyZWEsIG5hLnJtID0gVFJVRSkNCg0KcG5nKCJjb3JyZWxhdGlvbl9wbG90LnBuZyIsIHdpZHRoPTI1MDAsIGhlaWdodD0yNTAwLCByZXM9MTUwKQ0KcGFpcnMucGFuZWxzKE1WX3plcm8sIGNvbD0icmVkIikNCmRldi5vZmYoKQ0KDQoNCg0KcGxvdChkZW5zaXR5KE1WX3plcm8kWWVhckJ1aWx0KSwgY29sPSJyZWQiLCANCiBtYWluPSJZZWFyQnVpbHQgT3JpZ2luYWwgKEJsdWUpIHZzIFRyYW5zZm9ybWVkIChSZWQpIikgDQpsaW5lcyhkZW5zaXR5KGhvdXNpbmd2YWx1YXRpb24kWWVhckJ1aWx0LCBuYS5ybSA9IFRSVUUpLCBjb2w9ImJsdWUiKQ0KDQpwbG90KGRlbnNpdHkoTVZfemVybyRMaXZpbmdBcmVhKSwgY29sPSJyZWQiLCANCiBtYWluPSJMaXZpbmdBcmVhIE9yaWdpbmFsIChCbHVlKSB2cyBUcmFuc2Zvcm1lZCAoUmVkKSIpIA0KbGluZXMoZGVuc2l0eShob3VzaW5ndmFsdWF0aW9uJExpdmluZ0FyZWEsIG5hLnJtID0gVFJVRSksIGNvbD0iYmx1ZSIpDQpgYGANCg0KDQpgYGB7cn0NCiNmaW5hbCBkYXRhc2V0DQoNCmhvdXNpbmd2YWx1YXRpb24gPC0gaG91c2luZ3ZhbHVhdGlvblssICFuYW1lcyhob3VzaW5ndmFsdWF0aW9uKSAlaW4lIGMoIklkIildDQoNCmhvdXNpbmd2YWx1YXRpb25fY29tcGxldGUgPC0gaG91c2luZ3ZhbHVhdGlvbltjb21wbGV0ZS5jYXNlcyhob3VzaW5ndmFsdWF0aW9uKSxdDQoNCnN1bW1hcnkoaG91c2luZ3ZhbHVhdGlvbl9jb21wbGV0ZSkNCg0KDQoNCmBgYA0KDQoNCiNQYXJ0IEIgLSBRdWVzdGlvbiA1DQpgYGB7cn0NCiNDb3JyZWxhdGlvbiANCg0KY29ycGxvdCA8LSBjb3IoaG91c2luZ3ZhbHVhdGlvbl9jb21wbGV0ZSwgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpDQpjb3Jfcm91bmRlZCA8LSByb3VuZChjb3JwbG90LCBkaWdpdHMgPSAyKQ0KDQpjb3JycGxvdChjb3Jfcm91bmRlZCwgDQogICAgICAgICBtZXRob2QgPSAiY2lyY2xlIiwgDQogICAgICAgICB0eXBlID0gInVwcGVyIiwgDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCANCiAgICAgICAgIHRsLnNydCA9IDQ1LCANCiAgICAgICAgIG51bWJlci5jZXggPSAwLjcsDQogICAgICAgICB0bC5jZXggPSAwLjQsDQogICAgICAgICBjbC5jZXggPSAwLjQsDQogICAgICAgICBkaWFnID0gRkFMU0UsDQogICAgICAgICBvcmRlciA9ICJoY2x1c3QiLA0KICAgICAgICAgYWRkcmVjdCA9IDMsDQogICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKGMoIiM2RDlFQzEiLCAid2hpdGUiLCAiI0U0NjcyNiIpKSgyMDApKQ0KYGBgDQoNCg0KYGBge3J9DQojRGltZW5zaW9uYWwgcmVkdWN0aW9uIA0KDQp0YXJnZXRfdmFyIDwtIGhvdXNpbmd2YWx1YXRpb25fY29tcGxldGUkU2FsZVByaWNlDQoNCmhvdXNpbmdkYXRhc2V0ID0gc3Vic2V0KGhvdXNpbmd2YWx1YXRpb25fY29tcGxldGUsIHNlbGVjdCA9IC1jKFNhbGVQcmljZSkpDQoNCnN1bW1hcnkoaG91c2luZ2RhdGFzZXQpDQoNCg0KDQpNYXQgPC0gZGF0YS5tYXRyaXgoaG91c2luZ2RhdGFzZXQpDQoNCmNvcnJNYXQgPC0gY29yKE1hdCkNCg0KaGlnaGx5Q29yciA8LSBmaW5kQ29ycmVsYXRpb24oY29yck1hdCwgY3V0b2ZmID0gMC41KQ0KDQpuYW1lcyhob3VzaW5nZGF0YXNldClbaGlnaGx5Q29ycl0NCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQoNCnNlbGVjdGVkX2F0dHIgPC0gaG91c2luZ3ZhbHVhdGlvbl9jb21wbGV0ZSRTYWxlUHJpY2UNCnBhcihtZnJvdz1jKDEsMikpDQpoaXN0KHNlbGVjdGVkX2F0dHIsIGNvbD0ib3JhbmdlIiwgbWFpbj0iSGlzdG9ncmFtIikNCnBsb3QoZGVuc2l0eShzZWxlY3RlZF9hdHRyLCBuYS5ybT1UUlVFKSwgbWFpbj0iRGVuc2l0eSIpDQoNCg0KI0Rpc3RyaWJ1dGlvbiBvZiBzZWxlY3RlZCB2YXJpYWJsZXMgYWdhaW5zdCB0aGUgdGFyZ2V0IHZhcmlhYmxlDQpTZWxlY3RlZF92YXJzIDwtIHN1YnNldChob3VzaW5nZGF0YXNldCwgc2VsZWN0ID0gLWMoS2l0Y2hlbkFidkdyLCBVdGlsaXRpZXNfTm9TZVdhLCBBdHRhY2hlZHRvaG9tZV9nYXJhZ2UsIE1vU29sZCwgWXJTb2xkLCBHYXJhZ2VDYXJzKSkNCg0KU2VsZWN0ZWRfdmFycyRTYWxlUHJpY2UgPC0gdGFyZ2V0X3Zhcg0KDQojRGlzdHJpYnV0aW9uIG9mIGNvbnRpbm91cyB2YXJzIHdpdGggdGFyZ2V0IHZhcg0KDQpjb250aW51b3VzX3ZhcnMyIDwtIGMoIkxvdEFyZWEiLCAiVG90YWxCU0YiLCAiTGl2aW5nQXJlYSIsICJPcGVuUG9yY2hTRiIsICJMb3dRdWFsRmluU0YiLCAiUG9vbEFyZWEiKQ0KDQpwYXIobWZyb3cgPSBjKDIsIDMpKQ0KcGxvdF9saXN0IDwtIGxpc3QoKQ0KDQpmb3IgKHZhciBpbiBjb250aW51b3VzX3ZhcnMyKSB7DQogIHAgPC0gZ2dwbG90KFNlbGVjdGVkX3ZhcnMsIGFlc19zdHJpbmcoeCA9IHZhciwgeSA9ICJTYWxlUHJpY2UiKSkgKw0KICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIGNvbG9yID0gInN0ZWVsYmx1ZSIpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICJyZWQiLCBzZSA9IEZBTFNFKSArDQogICAgbGFicyh4ID0gdmFyLCB5ID0gIlNhbGUgUHJpY2UiLCB0aXRsZSA9IHBhc3RlKCJTYWxlIFByaWNlIHZzIiwgdmFyKSkgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksDQogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwNCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQ0KICANCiAgcGxvdF9saXN0W1t2YXJdXSA8LSBwDQp9DQpncmlkLmFycmFuZ2UoZ3JvYnMgPSBwbG90X2xpc3QsIG5jb2wgPSAzKQ0KDQoNCiNEaXN0cmlidXRpb24gb2YgY2F0ZWdvcmljYWwgdmFycyB3aXRoIHRhcmdldCB2YXINCg0KY2F0ZWdvcmljYWxfdmFyczIgPC0gU2VsZWN0ZWRfdmFycyAlPiUNCiAgc2VsZWN0KC1jKExvdEFyZWEsIFRvdGFsQlNGLCBMaXZpbmdBcmVhLCBPcGVuUG9yY2hTRiwgTG93UXVhbEZpblNGLCBQb29sQXJlYSwgU2FsZVByaWNlKSkNCg0KDQpwbG90X2RhdGEgPC0gY2F0ZWdvcmljYWxfdmFyczIgJT4lDQogIG11dGF0ZShTYWxlUHJpY2UgPSBTZWxlY3RlZF92YXJzJFNhbGVQcmljZSkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gLVNhbGVQcmljZSwgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAiQ2F0ZWdvcnkiKSAlPiUNCiAgZ3JvdXBfYnkoVmFyaWFibGUsIENhdGVnb3J5KSAlPiUNCiAgc3VtbWFyaXNlKE1lYW5TYWxlUHJpY2UgPSBtZWFuKFNhbGVQcmljZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KcGxvdF9saXN0IDwtIGxhcHBseSh1bmlxdWUocGxvdF9kYXRhJFZhcmlhYmxlKSwgZnVuY3Rpb24odmFyKSB7DQogIGdncGxvdChwbG90X2RhdGFbcGxvdF9kYXRhJFZhcmlhYmxlID09IHZhcixdLCBhZXMoeCA9IENhdGVnb3J5LCB5ID0gTWVhblNhbGVQcmljZSkpICsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gNiksDQogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLA0KICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAuMSwgMC4xLCAwLjEsIDAuMSksICJjbSIpKSArDQogICAgbGFicyh0aXRsZSA9IHZhciwgeCA9IE5VTEwsIHkgPSBOVUxMKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdChzY2FsZSA9IDFlLTMsIHN1ZmZpeCA9ICJLIikpDQp9KQ0KDQpuX3Bsb3RzIDwtIGxlbmd0aChwbG90X2xpc3QpDQpuX2NvbHMgPC0gY2VpbGluZyhzcXJ0KG5fcGxvdHMpKQ0Kbl9yb3dzIDwtIGNlaWxpbmcobl9wbG90cyAvIG5fY29scykNCg0KY2F0X2RpcyA8LSBncmlkLmFycmFuZ2UoDQogIGdyb2JzID0gcGxvdF9saXN0LA0KICBuY29sID0gbl9jb2xzLA0KICBucm93ID0gbl9yb3dzLA0KICB0b3AgPSAiRGlzdHJpYnV0aW9uIG9mIENhdGVnb3JpY2FsIFZhcmlhYmxlcyB2cyBTYWxlUHJpY2UiDQopDQoNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KI1Rlc3QgZm9yIHNrZXduZXNzDQoNCmhvdXNpbmdkYXRhc2V0ICU+JQ0KICBzZWxlY3QoYWxsX29mKGNvbnRpbnVvdXNfdmFyczIpKSAlPiUNCiAgZ2F0aGVyKGtleSA9ICJ2YXJpYWJsZSIsIHZhbHVlID0gInZhbHVlIikgJT4lDQogIGdncGxvdChhZXMoeCA9IHZhbHVlKSkgKw0KICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlIikgKw0KICBnZW9tX2hpc3RvZ3JhbSgpDQoNCmNhdGVnb3JpY2FsX3ZhcjMgPC0gY29sbmFtZXMoY2F0ZWdvcmljYWxfdmFyczIpDQoNCmhvdXNpbmdkYXRhc2V0ICU+JQ0KICBzZWxlY3QoYWxsX29mKGNhdGVnb3JpY2FsX3ZhcjMpKSAlPiUNCiAgZ2F0aGVyKGtleSA9ICJ2YXJpYWJsZSIsIHZhbHVlID0gInZhbHVlIikgJT4lDQogIGdncGxvdChhZXMoeCA9IHZhbHVlKSkgKw0KICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlIikgKw0KICBnZW9tX2JhcigpDQpgYGANCg0KDQpgYGB7cn0NCiNUcmFuZm9ybSB0byBub3JtYWwgZGlzdHJpYnV0aW9uDQoNCnJpZ2h0X3NrZXdjb2xzIDwtIGMoIkxpdmluZ0FyZWEiLCAiT3BlblBvcmNoU0YiLCAiVG90YWxCU0YiLCAiTG90QXJlYSIpDQoNCmhvdXNpbmdkYXRhc2V0W3JpZ2h0X3NrZXdjb2xzXSA8LSBsYXBwbHkoaG91c2luZ2RhdGFzZXRbcmlnaHRfc2tld2NvbHNdLCBmdW5jdGlvbih4KSB7DQogIHhbeCA8PSAwXSA8LSAwLjAxDQogIGxvZyh4KQ0KfSkNCg0KDQpob3VzaW5nZGF0YXNldCAlPiUNCiAgc2VsZWN0KGFsbF9vZihjb250aW51b3VzX3ZhcnMyKSkgJT4lDQogIGdhdGhlcihrZXkgPSAidmFyaWFibGUiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSkpICsNCiAgZmFjZXRfd3JhcCh+IHZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KDQoNCmBgYA0KDQoNCg0KI1BhcnQgQy0gcXVlc3Rpb24gMQ0KDQpgYGB7cn0NCg0KaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWQxIDwtIHN1YnNldChob3VzaW5nZGF0YXNldCwgc2VsZWN0ID0gLWMoS2l0Y2hlbkFidkdyLCBVdGlsaXRpZXNfTm9TZVdhLCBBdHRhY2hlZHRvaG9tZV9nYXJhZ2UsIE1vU29sZCwgWXJTb2xkLCBHYXJhZ2VDYXJzKSkNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpob3VzaW5nZGF0YXNldF9zZWxlY3RlZDEkU2FsZVByaWNlIDwtIHRhcmdldF92YXINCg0Kc3VtbWFyeShob3VzaW5nZGF0YXNldF9zZWxlY3RlZDEpDQoNCiNTZXQgdXAgc2FtcGxlDQoNCnNhbXBsZV9zaXplIDwtIGZsb29yKDIvMyAqIG5yb3coaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWQxKSkNCg0KDQojc2FtcGxlIHRoZSBkYXRhc2V0DQoNCnNldC5zZWVkKDYpIA0KDQoNCmhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkMSA8LSBob3VzaW5nZGF0YXNldF9zZWxlY3RlZDFbc2FtcGxlKG5yb3coaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWQxKSksIF0NCnRyYWluLnNldCA8LWhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkMVsxOnNhbXBsZV9zaXplLCBdDQp0ZXN0LnNldCA8LSBob3VzaW5nZGF0YXNldF9zZWxlY3RlZDFbKHNhbXBsZV9zaXplKzEpOm5yb3coaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWQxKSwgXQ0KDQoNCiNwcmVkaWN0aXZlIG1vZGVsIA0KDQpmb3JtdWxhID0gU2FsZVByaWNlIH4uDQoNCiNGaXQgdGhlIG1vZGVsDQoNCmhtb2RlbCA8LSBsbShmb3JtdWxhID0gZm9ybXVsYSwgZGF0YSA9IHRyYWluLnNldCkNCnN1bW1hcnkoaG1vZGVsKSRjb2VmZmljaWVudHMNCg0KI1JlZ3Jlc3Npb24gbW9kZWwNCg0KYXMuZm9ybXVsYSgNCiAgcGFzdGUwKCJ5IH4gIiwgcm91bmQoY29lZmZpY2llbnRzKGhtb2RlbClbMV0sMiksICIgKyAiLCANCiAgICAgICAgIHBhc3RlKHNwcmludGYoIiUuMmYgKiAlcyIsY29lZmZpY2llbnRzKGhtb2RlbClbLTFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMoY29lZmZpY2llbnRzKGhtb2RlbClbLTFdKSksIA0KICAgICAgICAgICAgICAgY29sbGFwc2U9IiArICIpDQogICkNCikNCg0KI1ByZWRpY3QgdGhlIFNhbGVQcmljZQ0KDQp0cmFpbi5zZXQkcHJlZGljdGVkLlNhbGVQcmljZSA8LSBwcmVkaWN0KGhtb2RlbCwgdHJhaW4uc2V0KQ0KdGVzdC5zZXQkcHJlZGljdGVkLlNhbGVQcmljZSA8LSBwcmVkaWN0KGhtb2RlbCwgdGVzdC5zZXQpDQoNCg0KcHJpbnQoIkFjdHVhbCBWYWx1ZXMiKQ0KaGVhZCh0ZXN0LnNldCRTYWxlUHJpY2VbMTo1XSkNCnByaW50KCJQcmVkaWN0ZWQgVmFsdWVzIikNCmhlYWQodGVzdC5zZXQkcHJlZGljdGVkLlNhbGVQcmljZVsxOjVdKQ0KDQojUGxvdCBwcmVkaWN0ZWQgdmFsdWUNCg0KcGxvdF8xIDwtIHRlc3Quc2V0ICU+JSANCiAgZ2dwbG90KGFlcyhTYWxlUHJpY2UscHJlZGljdGVkLlNhbGVQcmljZSkpICsgDQogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIA0KICBzdGF0X3Ntb290aChhZXMoY29sb3VyPSdyZWQnKSkgKyANCiAgeGxhYignQWN0dWFsIHZhbHVlIG9mIFNhbGVQcmljZScpICsgDQogIHlsYWIoJ1ByZWRpY3RlZCB2YWx1ZSBvZiBTYWxlUHJpY2UnKSsgDQogIHRoZW1lX2J3KCkNCmdncGxvdGx5KHBsb3RfMSkNCg0KDQojVGVzdGluZyBtb2RlbA0KZXJyb3IgPC0gdGVzdC5zZXQkU2FsZVByaWNlLXRlc3Quc2V0JHByZWRpY3RlZC5TYWxlUHJpY2UNCnJtc2UgPC0gc3FydChtZWFuKGVycm9yXjIpKQ0KcHJpbnQocGFzdGUoIlJvb3QgTWVhbiBTcXVhcmUgRXJyb3I6ICIsIHJtc2UpKQ0KDQoNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCg0KI21vZGVsIDINCg0KDQpob3VzaW5nZGF0YXNldF9zZWxlY3RlZDIgPC0gc3Vic2V0KGhvdXNpbmdkYXRhc2V0LCBzZWxlY3QgPSAtYyhLaXRjaGVuQWJ2R3IsIE1vU29sZCwgWXJTb2xkLCBBdHRhY2hlZHRvaG9tZV9nYXJhZ2UsIFV0aWxpdGllc19Ob1NlV2EsIExvdENvbmZpZ19JbnNpZGUsIER3ZWxsY2xhc3NfVG93bmhvdXNlX0luc2lkZVVuaXRlLCBHYXJhZ2VDYXJzKSkNCg0KDQpob3VzaW5nZGF0YXNldF9zZWxlY3RlZDIkU2FsZVByaWNlIDwtIHRhcmdldF92YXINCg0KDQojU2V0IHVwIHNhbXBsZQ0KDQoNCnNhbXBsZV9zaXplMiA8LSBmbG9vcigyLzMgKiBucm93KGhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkMikpDQoNCg0KI3NhbXBsZSB0aGUgZGF0YXNldA0KDQpzZXQuc2VlZCg2KQ0KDQpob3VzaW5nZGF0YXNldF9zZWxlY3RlZDIgPC0gaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWQyW3NhbXBsZShucm93KGhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkMikpLCBdDQoNCnRyYWluLnNldDIgPC1ob3VzaW5nZGF0YXNldF9zZWxlY3RlZDJbMTpzYW1wbGVfc2l6ZTIsIF0NCnRlc3Quc2V0MiA8LSBob3VzaW5nZGF0YXNldF9zZWxlY3RlZDJbKHNhbXBsZV9zaXplMisxKTpucm93KGhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkMiksIF0NCg0KDQoNCiNwcmVkaWN0aXZlIG1vZGVsIA0KDQpmb3JtdWxhID0gU2FsZVByaWNlIH4uDQoNCiNGaXIgdGhlIG1vZGVsDQoNCmhtb2RlbDIgPC0gbG0oZm9ybXVsYSA9IGZvcm11bGEsIGRhdGEgPSB0cmFpbi5zZXQyKQ0Kc3VtbWFyeShobW9kZWwyKSRjb2VmZmljaWVudHMNCg0KI1JlZ3Jlc3Npb24gbW9kZWwNCg0KYXMuZm9ybXVsYSgNCiAgcGFzdGUwKCJ5IH4gIiwgcm91bmQoY29lZmZpY2llbnRzKGhtb2RlbDIpWzFdLDIpLCAiICsgIiwgDQogICAgICAgICBwYXN0ZShzcHJpbnRmKCIlLjJmICogJXMiLGNvZWZmaWNpZW50cyhobW9kZWwyKVstMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyhjb2VmZmljaWVudHMoaG1vZGVsMilbLTFdKSksIA0KICAgICAgICAgICAgICAgY29sbGFwc2U9IiArICIpDQogICkNCikNCiNQcmVkaWN0IHRoZSBTYWxlUHJpY2UNCnJtKHRyYWluLnNldDIsIHRlc3Quc2V0MikNCg0KdHJhaW4uc2V0MiRwcmVkaWN0ZWQuU2FsZVByaWNlIDwtIHByZWRpY3QoaG1vZGVsMiwgdHJhaW4uc2V0MikNCnRlc3Quc2V0MiRwcmVkaWN0ZWQuU2FsZVByaWNlIDwtIHByZWRpY3QoaG1vZGVsMiwgdGVzdC5zZXQyKQ0KDQpwcmludCgiQWN0dWFsIFZhbHVlcyIpDQpoZWFkKHRlc3Quc2V0MiRTYWxlUHJpY2VbMTo1XSkNCnByaW50KCJQcmVkaWN0ZWQgVmFsdWVzIikNCmhlYWQodGVzdC5zZXQyJHByZWRpY3RlZC5TYWxlUHJpY2VbMTo1XSkNCg0KI1Bsb3QgcHJlZGljdGVkIHZhbHVlDQpwbG90XzIgPC0gdGVzdC5zZXQyICU+JSANCiAgZ2dwbG90KGFlcyhTYWxlUHJpY2UscHJlZGljdGVkLlNhbGVQcmljZSkpICsgDQogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIA0KICBzdGF0X3Ntb290aChhZXMoY29sb3VyPSdyZWQnKSkgKyANCiAgeGxhYignQWN0dWFsIHZhbHVlIG9mIFNhbGVQcmljZScpICsgDQogIHlsYWIoJ1ByZWRpY3RlZCB2YWx1ZSBvZiBTYWxlUHJpY2UnKSsgDQogIHRoZW1lX2J3KCkNCmdncGxvdGx5KHBsb3RfMikNCg0KDQojVGVzdGluZyBtb2RlbA0KDQpybShlcnJvcjIsIHJtc2UyKQ0KDQplcnJvcjIgPC0gdGVzdC5zZXQyJFNhbGVQcmljZS10ZXN0LnNldDIkcHJlZGljdGVkLlNhbGVQcmljZQ0Kcm1zZTIgPC0gc3FydChtZWFuKGVycm9yMl4yKSkNCnByaW50KHBhc3RlKCJSb290IE1lYW4gU3F1YXJlIEVycm9yXzI6ICIsIHJtc2UyKSkNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KDQojbW9kZWwgMw0KDQoNCmhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkXzMgPC0gc3Vic2V0KGhvdXNpbmdkYXRhc2V0LCBzZWxlY3QgPSAtYyhLaXRjaGVuQWJ2R3IsIE1vU29sZCwgWXJTb2xkLCBBdHRhY2hlZHRvaG9tZV9nYXJhZ2UsIFV0aWxpdGllc19Ob1NlV2EsIExvdENvbmZpZ19JbnNpZGUsIER3ZWxsY2xhc3NfVG93bmhvdXNlX0luc2lkZVVuaXRlLCBHYXJhZ2VDYXJzLCBVdGlsaXRpZXNfQWxsUHViKSkNCg0KaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWRfMyRTYWxlUHJpY2UgPC0gdGFyZ2V0X3Zhcg0KDQoNCiNTZXQgdXAgc2FtcGxlDQoNCg0Kc2FtcGxlX3NpemVfMyA8LSBmbG9vcigyLzMgKiBucm93KGhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkXzMpKQ0KDQoNCiNzYW1wbGUgdGhlIGRhdGFzZXQNCg0KDQpzZXQuc2VlZCg2KSANCg0KDQpob3VzaW5nZGF0YXNldF9zZWxlY3RlZF8zIDwtIGhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkXzNbc2FtcGxlKG5yb3coaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWRfMykpLCBdDQoNCnRyYWluLnNldDMgPC1ob3VzaW5nZGF0YXNldF9zZWxlY3RlZF8zWzE6c2FtcGxlX3NpemVfMywgXQ0KdGVzdC5zZXQzIDwtIGhvdXNpbmdkYXRhc2V0X3NlbGVjdGVkXzNbKHNhbXBsZV9zaXplXzMrMSk6bnJvdyhob3VzaW5nZGF0YXNldF9zZWxlY3RlZF8zKSwgXQ0KDQoNCg0KI3ByZWRpY3RpdmUgbW9kZWwgDQoNCmZvcm11bGEgPSBTYWxlUHJpY2Ugfi4NCg0KI0ZpciB0aGUgbW9kZWwNCg0KaG1vZGVsXzMgPC0gbG0oZm9ybXVsYSA9IGZvcm11bGEsIGRhdGEgPSB0cmFpbi5zZXQzKQ0KDQoNCnN1bW1hcnkoaG1vZGVsXzMpJGNvZWZmaWNpZW50cw0KDQojUmVncmVzc2lvbiBtb2RlbA0KDQphcy5mb3JtdWxhKA0KICBwYXN0ZTAoInkgfiAiLCByb3VuZChjb2VmZmljaWVudHMoaG1vZGVsXzMpWzFdLDIpLCAiICsgIiwgDQogICAgICAgICBwYXN0ZShzcHJpbnRmKCIlLjJmICogJXMiLGNvZWZmaWNpZW50cyhobW9kZWxfMylbLTFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMoY29lZmZpY2llbnRzKGhtb2RlbF8zKVstMV0pKSwgDQogICAgICAgICAgICAgICBjb2xsYXBzZT0iICsgIikNCiAgKQ0KKQ0KI1ByZWRpY3QgdGhlIFNhbGVQcmljZQ0KDQoNCnRyYWluLnNldDMkcHJlZGljdGVkLlNhbGVQcmljZSA8LSBwcmVkaWN0KGhtb2RlbF8zLCB0cmFpbi5zZXQzKQ0KdGVzdC5zZXQzJHByZWRpY3RlZC5TYWxlUHJpY2UgPC0gcHJlZGljdChobW9kZWxfMywgdGVzdC5zZXQzKQ0KDQoNCnByaW50KCJBY3R1YWwgVmFsdWVzIikNCmhlYWQodGVzdC5zZXQzJFNhbGVQcmljZVsxOjVdKQ0KcHJpbnQoIlByZWRpY3RlZCBWYWx1ZXMiKQ0KaGVhZCh0ZXN0LnNldDMkcHJlZGljdGVkLlNhbGVQcmljZVsxOjVdKQ0KDQojUGxvdCBwcmVkaWN0ZWQgdmFsdWUNCnBsb3QzIDwtIHRlc3Quc2V0MyAlPiUgDQogIGdncGxvdChhZXMoU2FsZVByaWNlLHByZWRpY3RlZC5TYWxlUHJpY2UpKSArIA0KICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyANCiAgc3RhdF9zbW9vdGgoYWVzKGNvbG91cj0ncmVkJykpICsgDQogIHhsYWIoJ0FjdHVhbCB2YWx1ZSBvZiBTYWxlUHJpY2UnKSArIA0KICB5bGFiKCdQcmVkaWN0ZWQgdmFsdWUgb2YgU2FsZVByaWNlJykrIA0KICB0aGVtZV9idygpDQpnZ3Bsb3RseShwbG90MykNCg0KDQojUnNxdWFyZSBhc3Nlc3NtZW50DQojVHJhaW4gbW9kZQ0Kcl9zcXVhcmVkIDwtIHN1bW1hcnkoaG1vZGVsKSRyLnNxdWFyZWQNCnByaW50KHBhc3RlKCJSIFNxdWFyZWQ6ICIsIHJfc3F1YXJlZCkpDQoNCg0KI1Rlc3RpbmcgbW9kZWwNCg0KDQoNCmVycm9yXzMgPC0gdGVzdC5zZXQzJFNhbGVQcmljZS10ZXN0LnNldDMkcHJlZGljdGVkLlNhbGVQcmljZQ0Kcm1zZV8zIDwtIHNxcnQobWVhbihlcnJvcl8zXjIpKQ0KcHJpbnQocGFzdGUoIlJvb3QgTWVhbiBTcXVhcmUgRXJyb3JfMjogIiwgcm1zZV8zKSkNCg0KYGBgDQoNCg0KI0RlY2lzaW9uIFRyZWUNCmBgYHtyfQ0KDQoNCmRjdGhvdXNpbmcgPC0gaG91c2luZ2RhdGFzZXRfc2VsZWN0ZWQxDQpWaWV3KGRjdGhvdXNpbmcpDQpnZ2NvcnIoZGN0aG91c2luZywgbGFiZWwgPSBUUlVFKQ0KDQoNCg0KYGBgDQoNCg0KDQoNCg0KYGBge3J9DQoNCmRjdHNhbXBsZSA8LSBmbG9vcigyLzMqbnJvdyhkY3Rob3VzaW5nKSkNCg0Kc2V0LnNlZWQoNikgDQoNCg0KZGN0aG91c2luZy5zZWxlY3RlZCA8LSBkY3Rob3VzaW5nW3NhbXBsZShucm93KGRjdGhvdXNpbmcpKSwgXQ0KDQpkY3QudHJhaW4gPC0gZGN0aG91c2luZy5zZWxlY3RlZFsxOmRjdHNhbXBsZSwgXSAgDQpkY3QudGVzdCA8LSBkY3Rob3VzaW5nLnNlbGVjdGVkWyhkY3RzYW1wbGUrMSk6bnJvdyhkY3Rob3VzaW5nLnNlbGVjdGVkKSwgXSANCg0KDQoNCmZvcm11bGEgPSBTYWxlUHJpY2Ugfi4NCg0KZHRyZWUgPC0gcnBhcnQoZm9ybXVsYSwgZGF0YT1kY3QudHJhaW4sIG1ldGhvZD0iYW5vdmEiKQ0KDQpkdHJlZSR2YXJpYWJsZS5pbXBvcnRhbmNlDQpgYGANCg0KDQpgYGB7cn0NCg0KcnBhcnQucGxvdChkdHJlZSwgdHlwZSA9IDQsIGZhbGxlbi5sZWF2ZXMgPSBGQUxTRSkNCg0KcHJpbnQoZHRyZWUpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQoNCnByZWRpY3RlZC5kY3RTYWxlUHJpY2UgPC0gcHJlZGljdChkdHJlZSwgZGN0LnRlc3QpDQoNCnByaW50KCJBY3R1YWwgVmFsdWVzIikNCmhlYWQoZGN0LnRlc3QkU2FsZVByaWNlWzE6NV0pDQpwcmludCgiUHJlZGljdGVkIFZhbHVlcyIpDQpoZWFkKHByZWRpY3RlZC5kY3RTYWxlUHJpY2VbMTo1XSkNCg0KDQoNCg0KZGN0X2Vycm9yIDwtIGRjdC50ZXN0JFNhbGVQcmljZSAtIHByZWRpY3RlZC5kY3RTYWxlUHJpY2UNCmRjdF9ybXNlIDwtIHNxcnQobWVhbihkY3RfZXJyb3JeMikpDQpwcmludChwYXN0ZSgiUm9vdCBNZWFuIFNxdWFyZSBFcnJvcjogIiwgZGN0X3Jtc2UpKQ0KDQojQ1ANCnByaW50Y3AoZHRyZWUpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQpiZXN0X2NwIDwtIGR0cmVlJGNwdGFibGVbd2hpY2gubWluKGR0cmVlJGNwdGFibGVbLCJ4ZXJyb3IiXSksIkNQIl0NCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgVHJ5IGEgaGlnaGVyIENQIHZhbHVlIC0gYmVzdA0KDQpwcnVuZWRfZHRyZWUyIDwtIHBydW5lKGR0cmVlLCBjcCA9ICAwLjAxNDEwMikNCnByZWQyIDwtIHByZWRpY3QocHJ1bmVkX2R0cmVlMiwgZGN0LnRlc3QpDQpybXNlMiA8LSBzcXJ0KG1lYW4oKGRjdC50ZXN0JFNhbGVQcmljZSAtIHByZWQyKV4yKSkNCnByaW50KHBhc3RlKCJSTVNFIHdpdGggaGlnaGVyIENQOiIsIHJtc2UyKSkNCg0KIyBUcnkgYSBsb3dlciBDUCB2YWx1ZSANCnBydW5lZF9kdHJlZTMgPC0gcHJ1bmUoZHRyZWUsIGNwID0gMC4wMDkwMCkNCnByZWQzIDwtIHByZWRpY3QocHJ1bmVkX2R0cmVlMywgZGN0LnRlc3QpDQpybXNlMyA8LSBzcXJ0KG1lYW4oKGRjdC50ZXN0JFNhbGVQcmljZSAtIHByZWQzKV4yKSkNCnByaW50KHBhc3RlKCJSTVNFIHdpdGggbG93ZXIgQ1A6Iiwgcm1zZTMpKQ0KDQoNCnJwYXJ0LnBsb3QocHJ1bmVkX2R0cmVlMiwgdHlwZSA9IDQsIGZhbGxlbi5sZWF2ZXMgPSBGQUxTRSkNCnJwYXJ0LnBsb3QocHJ1bmVkX2R0cmVlMywgdHlwZSA9IDQsIGZhbGxlbi5sZWF2ZXMgPSBGQUxTRSkNCnJwYXJ0LnBsb3QoZHRyZWUsIHR5cGUgPSA0LCBmYWxsZW4ubGVhdmVzID0gRkFMU0UpDQoNCg0KDQpgYGANCg0K